// package des 简化DES加密步骤，隐藏加密细节
package des

import (
	"crypto/des"

	"github.com/pkg/errors"
)

// EncryptECB 加密，使用ECB模式
func EncryptECB(plainText []byte, key []byte) ([]byte, error) {
	text := paddingPKCS5(plainText)
	cipherText := make([]byte, len(text))

	block, err := des.NewCipher(key)
	if err != nil {
		return nil, errors.Wrap(err, "the length of key must be 8")
	}

	blockSize := block.BlockSize()
	for i, count := 0, len(text)/blockSize; i < count; i++ {
		begin, end := i*blockSize, i*blockSize+blockSize
		block.Encrypt(cipherText[begin:end], text[begin:end])
	}

	return cipherText, nil
}

// DecryptECB 解密，使用ECB模式
func DecryptECB(cipherText []byte, key []byte) ([]byte, error) {
	text := make([]byte, len(cipherText))
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, errors.Wrap(err, "the length of key must be 8")
	}

	blockSize := block.BlockSize()
	for i, count := 0, len(text)/blockSize; i < count; i++ {
		begin, end := i*blockSize, i*blockSize+blockSize
		block.Decrypt(text[begin:end], cipherText[begin:end])
	}

	return unPaddingPKCS5(text), nil
}

// EncryptECBTriple 加密，使用三重数据加密算法（3DES），ECB模式
// key的长度必须是 16 或 24 bytes
func EncryptECBTriple(plainText []byte, key []byte) ([]byte, error) {
	if !(len(key) == 16 || len(key) == 24) {
		return nil, errors.New("key length must be 16 or 24")
	}

	text := paddingPKCS5(plainText)

	var newKey []byte
	if len(key) == 16 {
		newKey = append([]byte{}, key...)
		newKey = append(newKey, key[:8]...)
	} else {
		newKey = append([]byte{}, key...)
	}

	block, err := des.NewTripleDESCipher(newKey)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	cipherText := make([]byte, len(text))
	for i, count := 0, len(text)/blockSize; i < count; i++ {
		begin, end := i*blockSize, i*blockSize+blockSize
		block.Encrypt(cipherText[begin:end], text[begin:end])
	}
	return cipherText, nil
}

// EncryptECBTriple 解密，使用三重数据加密算法（3DES），ECB模式
// key的长度必须是 16 或 24 bytes
func DecryptECBTriple(cipherText []byte, key []byte) ([]byte, error) {
	if !(len(key) == 16 || len(key) == 24) {
		return nil, errors.New("key length must be 16 or 24")
	}

	var newKey []byte
	if len(key) == 16 {
		newKey = append([]byte{}, key...)
		newKey = append(newKey, key[:8]...)
	} else {
		newKey = append([]byte{}, key...)
	}

	block, err := des.NewTripleDESCipher(newKey)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	text := make([]byte, len(cipherText))
	for i, count := 0, len(text)/blockSize; i < count; i++ {
		begin, end := i*blockSize, i*blockSize+blockSize
		block.Decrypt(text[begin:end], cipherText[begin:end])
	}
	return unPaddingPKCS5(text), nil
}
